package at.fhooe.stefanirndorfer.entity;


import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Random;

import org.lwjgl.BufferUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;

import static org.lwjgl.opengl.GL11.*;
import at.fhooe.stefanirndorfer.effects.LowPassFilter;
import at.fhooe.stefanirndorfer.engine.game.Game;
import at.fhooe.stefanirndorfer.sound.OpenALUtil;
import at.fhooe.stefanirndorfer.sound.SoundManager;
import at.fhooe.stefanirndorfer.sound.SimpleSoundSoundPlayer;
import at.stefanirndorfer.openaltest.entity.Entity;
import at.stefanirndorfer.openaltest.input.InputManager;
import at.stefanirndorfer.openaltest.input.KeyInputListener;
import at.stefanirndorfer.openaltest.input.MouseInputListener;
import at.stefanirndorfer.openaltest.logging.Log;

@SuppressWarnings("unused")
public class Rectangle extends Entity implements KeyInputListener, MouseInputListener{
	
	private static final int NUM_REFLECTIONS = 4;
	private static final int STEPWIDTH = 5;
	
	
	
	float [] color;
	
	int windowWidth;
	int windowHeight;
	private boolean isInBounds;
	private boolean selected;
	
	//sound stuff
	private SoundManager sm;
	private String[] soundIds;
	private boolean hasSoundReflections;
	
	
	SimpleSoundSoundPlayer soundPlayer;
	CircleReflection[] cr;
	
	InputManager im;
	
	//TODO on Destroy muss der soundPlayer terminiert werden (sourceBuffer und was ist mit buffer?)
	
	public Rectangle(int width, int height, double initPositionX, double initPositionY, float[] color){
		super(width, height, initPositionX, initPositionY);
		im = Game.getInstance().getInputManager();
		this.color = randomizeColor();

		//in order to process input
		setUpKeyInputListener();
		setUpMouseInputListener();
		windowWidth = Game.getInstance().getWindow().getWindowWidth();
		windowHeight = Game.getInstance().getWindow().getWindwoHeight();
		
		isInBounds = false;
		selected = false;
		
		sm = Game.getInstance().getSoundManager();
		initSoundIds();
	
		soundPlayer = new SimpleSoundSoundPlayer(sm, soundIds, windowWidth, windowHeight, posX, posY);
		hasSoundReflections = true;
		if(hasSoundReflections) initReflections();
	}

	private void initReflections() {
		cr = new CircleReflection[NUM_REFLECTIONS];
		for (int i = 0; i < NUM_REFLECTIONS; i++) {
			cr[i] = new CircleReflection(40, 40, posX + i*30, posY + i*30, randomizeColor(), soundIds);
		}
		
	}

	private float[] randomizeColor() {
		float[] ret = new float[3];
		Random rand = new Random();
		ret[0] = rand.nextFloat();
		ret[1] = rand.nextFloat();
		ret[2] = rand.nextFloat();
		return ret;
	}



	@Override
	public void setUpMouseInputListener() {
		Game.getInstance().getInputManager().addMouseListener(this);
	}

	@Override
	public void tearDownMouseInputListener(MouseInputListener il) {
		Game.getInstance().getInputManager().removeMouseListener(this);		
	}


	@Override
	public void setUpKeyInputListener() {
		Game.getInstance().getInputManager().addKeyListener(this);				
	}

	@Override
	public void tearDownKeyInputListener(KeyInputListener il) {
		Game.getInstance().getInputManager().removeKeyListener(this);		
		
	}

	@Override
	public void processKeyInput(int eventKey, boolean keyDown) {
		if(keyDown){
			if(eventKey == Keyboard.KEY_UP && keyDown){
				posY += STEPWIDTH;
			}
			if(eventKey == Keyboard.KEY_DOWN && keyDown){
				posY -= STEPWIDTH;
			}
			if(eventKey == Keyboard.KEY_LEFT && keyDown){
				posX -= STEPWIDTH;
			}
			if(eventKey == Keyboard.KEY_RIGHT && keyDown){
				posX += STEPWIDTH;
			}
			if(eventKey == Keyboard.KEY_1 && keyDown){
				String sId = "tractor_beam";
				//soundPlayer.play(sId);
				soundPlayer.playWithReverb(sId, 0.5f);
				if(hasSoundReflections) playReflections(sId);
			}
			if(eventKey == Keyboard.KEY_2 && keyDown){
				String sId = "Repair";
				//soundPlayer.play(sId);
				soundPlayer.playWithReverb(sId, 0.5f);
				if(hasSoundReflections) playReflections(sId);
			}
			
		}else{
			
		}
	}

	/**
	 * calculates the air absorbtion considering the calculated distance
	 * @param sId
	 */
	private void playReflections(String sId) {
		
		float lowPass_Gain, highFrequency_Gain;
		
		for (int i = 0; i < cr.length; i++) {
			cr[i].getSoundPlayerEFX().playDelayed(sId, new LowPassFilter(0.8f, 0.0f));
		}
	}

	@Override
	public void processMouseInput(int x, int y, int dx, int dy) {
		
		isOnThis(x, y);
		if(isInBounds){
			Log.info(this, "is in Bounds");
			if(Mouse.isButtonDown(0) && !selected){
				selected = true;
				Log.info(this, "isSelected");
		}else{
			if(!Mouse.isButtonDown(0)){
				selected = false;
				//Log.info(this, "isNotSelected");
			}
		}
			
		}
		if(selected && !Mouse.isButtonDown(0)){
			selected = !selected;
		}
	}


	private void isOnThis(int mX, int mY) {	
		mY = -mY;
		if( mX > posX && mX < posX+width && mY > posY && mY < posY + height ){
			isInBounds = true;
		}else{
			isInBounds = false;
		}
	}

	@Override
	public void render() {		
		glColor3f(color[0], color[1], color[2]);

		glBegin(GL_QUADS);
		glVertex2d(posX, posY);
		glVertex2d(posX + width, posY);
		glVertex2d(posX + width, posY + height);
		glVertex2d(posX, posY + height);
		glEnd();
	}

	@Override
	public void update(int delta) {
		if(selected){
			
			float oldX = (float) posX;
			float oldY = (float) posY;
			
			
			posX += im.dx;
			//mouse dy needs to be inverted
			posY += im.dy;
			
			float posXf = (float)(posX)- oldX;		
			float posYf = (float)(posY) - oldY;
			float[] sourceParams = new float[]{posXf, posYf};
			
			soundPlayer.updateSourceParams(sourceParams);
		}
		
		if(hasSoundReflections) updateReflectionDistances();
	}

	/**
	 * updates distances of all audio reflections
	 * called on each loop
	 */
	private void updateReflectionDistances() {
		
		double distToListener = soundPlayer.calculateDistancesToListener();
		
		for (int i = 0; i < NUM_REFLECTIONS; i++) {
			
			// Distance this source to reflection
			double totalDist = OpenALUtil.calcEuclDist(cr[i].getPosition(), soundPlayer.getSourcePos());
			
			// Distance this reflection to listener
			totalDist += OpenALUtil.calcEuclDist(cr[i].getPosition(), sm.getListenerPosition());
			totalDist -= distToListener;
			
			int ms = OpenALUtil.calcDelayFromDistance(totalDist);
			cr[i].getSoundPlayerEFX().setDelay(ms);
			System.out.println(totalDist/10 + "m is in ms: " + ms);
		}
	}

	@Override
	public double[] getPosition() {
		return new double[]{posX,posY};
	}

	/**
	 * sounds without ".wav" 
	 */
	private void initSoundIds() {
		this.soundIds = new String[]{
				"Repair",
				"tractor_beam",
		};
	}

}
